package com.eastmoney.emis.edda.infrastructure.report.service;

import com.eastmoney.emis.edda.config.HsbcEddaConfig;
import com.eastmoney.emis.edda.domain.valueobject.MandateStatus;
import com.eastmoney.emis.edda.domain.valueobject.TimeFormatter;
import com.eastmoney.emis.edda.infrastructure.hsbc.HsbcEddaApi;
import com.eastmoney.emis.edda.infrastructure.hsbc.dto.AccountDto;
import com.eastmoney.emis.edda.infrastructure.hsbc.dto.ReportsReq;
import com.eastmoney.emis.edda.infrastructure.hsbc.dto.ReportsResp;
import com.eastmoney.emis.edda.infrastructure.report.DDAReport;
import com.eastmoney.emis.edda.infrastructure.report.DDAReportRecord;
import com.eastmoney.emis.edda.infrastructure.report.ReportType;
import com.eastmoney.emis.edda.infrastructure.util.CsvUtils;
import com.eastmoney.emis.utils.common.enums.ApplicationStatus;
import com.eastmoney.emis.utils.common.exception.BusinessException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class ReportServiceImpl implements ReportService {
    private static Logger log = LoggerFactory.getLogger(ReportServiceImpl.class);
    @Resource
    private HsbcEddaApi hsbcEddaApi;
    @Resource
    private HsbcEddaConfig config;
    @Autowired
    private ApplicationEventPublisher publisher;
    @Autowired
    private ReportFileService reportFileService;


    public void processEddaReport(LocalDate date) {
        if (processCheck(date, ReportType.DDAReport)) {
            return;
        }
        ReportsReq reportsReq = new ReportsReq();
        reportsReq.ReportType = ReportType.DDAReport.name();
        String dateStr = date.format(TimeFormatter.YYYY_MM_DD);
        reportsReq.ReportingDate = dateStr;
        reportsReq.CreditorAccount = new AccountDto(config.getCreditorAccount());
        ReportsResp report = hsbcEddaApi.report(reportsReq);
        report.onSuccess(resp -> {
            try {
                byte[] zipBytes = report.getZipBytes();
                if (zipBytes.length == 0) {
                    log.info("dda-report content is empty, {}", resp);
                    return;
                }
                reportFileService.upload(zipBytes, dateStr, ReportType.DDAReport);

                List<String> dataList = report.decode().stream()
                        .flatMap(r -> CsvUtils.parse(r.getData()).stream()).collect(Collectors.toList());
                if (dataList.size() <= 1) {
                    return;
                }
                // 表头
                DDAReport ddaReport = new DDAReport(dataList.get(0));
                log.info("process dda-report, {}", ddaReport);
                List<DDAReportRecord> ddaReportRecords = dataList.stream()
                        .skip(1)
                        .map(DDAReportRecord::new)
                        .filter(this::filterErrorMandate)
                        .collect(Collectors.toList());
                ddaReport.setReportRecords(ddaReportRecords);
                publisher.publishEvent(ddaReport);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }

        }).onFail(r -> {
            log.error("request {} dda report error, {}", date, report.errors());
        });


    }

    @Override
    public void processEddiReport(LocalDate date) {
        if (processCheck(date, ReportType.DDIReport)) {
            return;
        }
        ReportsReq reportsReq = new ReportsReq();
        reportsReq.ReportType = ReportType.DDIReport.name();
        String dateStr = date.format(TimeFormatter.YYYY_MM_DD);
        reportsReq.ReportingDate = dateStr;
        reportsReq.CreditorAccount = new AccountDto(config.getCreditorAccount());
        ReportsResp report = hsbcEddaApi.report(reportsReq);
        report.onSuccess(resp -> {
            byte[] zipBytes = report.getZipBytes();
            if (zipBytes.length == 0) {
                log.info("dda-report content is empty, {}", resp);
                return;
            }
            reportFileService.upload(zipBytes, dateStr, ReportType.DDIReport);
        }).onFail(r -> {
            log.error("request {} ddi report error, {}", date, report.errors());
        });
    }

    private boolean filterErrorMandate(DDAReportRecord r) {
        MandateStatus mandateStatus = MandateStatus.parse(r.getMandateStatus());
        return mandateStatus == MandateStatus.CANCELLED ||
                mandateStatus == MandateStatus.DELETED ||
                mandateStatus == MandateStatus.EXPIRED;
    }

    private boolean processCheck(LocalDate date, ReportType reportType) {
        long period = date.until(LocalDate.now(), ChronoUnit.DAYS);
        if (period > 14 || period <= 0) {
            throw new BusinessException(ApplicationStatus.ILLEGAL_ARGUMENT_EXCEPTION.getStatus(), "不支持的时间范围区间");
        }
        return processed(date, reportType);
    }

    private boolean processed(LocalDate date, ReportType ddaReport) {
        return reportFileService.exists(date.format(TimeFormatter.YYYY_MM_DD), ddaReport);
    }


}
